package Stack_04.PolandNotation_04;

/*
 * @Author 罗
 * @date 2020/3/14 - 10:27 上午
 *
 */

import Stack_04.calculate_03.StackForCalculator;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class SuffixExpression_01 {

    @Test
    public void test(){
        /*
         * 先定义逆波兰表达式
         * (3+4)*5-6 -----> 3 4 + 5 * 6 -
         * 为了方便，逆波兰表达式的数字和符号使用空格隔开
         *      1.后缀表达式只能以运算符结尾，如果以空格结尾会报错
         *      2.注意运算符必须与实际运算的匹配 * x 不匹配
         * 4*5-8+60+8/2-----> 4 5 * 8 - 60 + 8 2 / +
         * */
        String suffixExpression = "3 4 + 5 * 6 -";
        String suffixExpression2 = "4 5 * 8 - 60 + 8 2 / +";
        /*
        * 1.先将"3 4 + 5 * 6 -"放入到ArrayList中
        * 2.将ArrayList传递给一个方法，遍历ArrayList，配合栈，完成计算
        *
        * */
        List <String> listString = getListString(suffixExpression2);
        for (String s : listString) {
            System.out.println(s);
        }

        double result = calculate(listString);
        System.out.println(result);
    }

    /**
     * 完成对波兰表达式的计算
     * 注意：弹出的次栈顶元素在计算式的前面
     *  次栈顶-栈顶、次栈顶/栈顶、次栈顶+栈顶、次栈顶*栈顶
     * 1.从左到右扫描表达式
     * 2.遇到数字时，将数字压入堆栈
     * 3.遇到运算符时，弹出栈中的两个元素（栈顶和次栈顶元素）
     *      并利用运算符对他们进行相应的计算(栈顶元素和次栈顶元素)
     *      并将结果压入堆栈
     * 4.重复上面的过程直到表达式的最右端
     * 5.最后算出的值即为表达式的结果
     *
     *
     * (1)从左向右扫描，将数字push()堆栈，3和4被压入堆栈
     * (2)遇到运算符(+)因此弹出4和3(4为栈顶元素，3为栈底元素)
     *      计算出3+4的值，得7，再将7压入堆栈
     * (3)将5压入堆栈
     * (4)遇到*运算符，弹出5和7，计算7*5=35，将35压入堆栈
     * (5)将6压入堆栈
     * (6)遇到运算符-，弹出6和35，计算35-6=29，得出结果
     * @param list
     * @return
     */
    public static double calculate(List<String> list){
        String temp ;

        Stack<Double> stack = new Stack<Double>();

        double result = 0;

        for (int i = 0; i < list.size(); i++) {
            temp = list.get(i);
            if(StackForCalculator.isOperation(temp.charAt(0))){
/*            运算符
                1.弹出次栈顶元素 (+,-,*,/) 栈顶元素
                    弹出来的元素直接放入计算方法，因为先弹出来的元素（栈顶）在计算方法中被放在
                    后弹出来的元素（次栈顶）的后面
 */
                result = StackForCalculator.calculate(stack.pop(),stack.pop(),temp.charAt(0));
//              2. 将计算结果压入堆栈
                stack.push(result);
            }else{
//                是数字，直接压入堆栈
                stack.push(Double.valueOf(temp));
            }
        }

        return stack.pop() ;
    }


    /**
     * 将一个逆波兰表达式，依次将数据和运算符放入到ArrayList中
     * @param suffixExpression
     * @return
     */
    public static List<String> getListString(String suffixExpression){
        List<String> listString = new ArrayList<>();

        /*
         *   有空格不用，而且这样获取到的数字只能是一位的
         *   for (int i = 0; i < suffixExpression.length(); i++) {
         *      listString.add(suffixExpression.substring(i,i+1));
         *   }
         *   用新方法
         */

        String[] symbol = suffixExpression.split(" ",0);

        for (String s : symbol) {
            listString.add(s);
        }
        return listString;
    }
}













